<template>
  <div class="board-container">
    <!-- 头部：左实时看板号等，右字段选择，两端对齐 -->
    <div class="board-header-row">
      <div class="board-header-info">
        <span>实时看板号:</span>
        <span class="board-num">{{ num }}</span>
        <span>已加入人数:</span>
        <span class="board-joined">{{ boradList.length }}人</span>
        <span class="board-date">{{ nowDate }}</span>
      </div>
      <div class="dropdown">
        <button @click="toggleDropdown" class="dropdown-btn">
          选择展示项目
        </button>
        <div v-if="showDropdown" ref="dropdownRef" class="dropdown-menu">
          <label
            v-for="(option, index) in options"
            :key="index"
            class="dropdown-item"
          >
            <input type="checkbox" v-model="option.checked" />
            {{ option.label }}
          </label>
        </div>
      </div>
    </div>
    <template v-if="isEffective">
      <p class="board-status">
        <span class="board-online-wrap"> 当前在线人数: </span>
        <span class="board-online">{{ onlineStuNum }}</span>
        <span class="board-offline-wrap"> 离线人员: </span>
        <span class="board-offline-names">{{
          offlineStuNames ? offlineStuNames : "无"
        }}</span>
      </p>
      <template v-if="boradList.length > 0">
        <div
          class="card-carousel"
          ref="cardContainerRef"
          @mouseenter="handleUserActive"
          @mouseleave="handleUserInactive"
          @mousedown="handleUserActive"
          @touchstart="handleUserActive"
          @mousemove="handleUserActive"
          @wheel="handleUserActive"
        >
          <transition name="arrow-fade">
            <button
              v-if="showArrows && totalPages > 1"
              class="carousel-arrow left"
              @click="handleManualSwitch('prev')"
              @mousedown.stop
            >
              <span class="arrow-icon">&lsaquo;</span>
            </button>
          </transition>
          <div class="card">
            <!-- 在 .card 内部最前面加 -->
            <div
              class="card-item virtual-card"
              ref="virtualCardRef"
              aria-hidden="true"
              style="
                position: absolute;
                z-index: -1;
                opacity: 0;
                pointer-events: none;
              "
            ></div>
            <div
              class="card-item"
              v-for="(item, index) in pagedList"
              :key="index"
              :ref="setCardItemRef"
            >
              <div class="card-title">
                <span class="card-nickname" :title="item.nickname">{{
                  item.nickname
                }}</span>
                <template v-if="item.status === 0">
                  <span v-if="showField('累计在线时长')"
                    >累计在线：{{ item.onlineTime }}</span
                  >
                </template>
                <template v-else>
                  <span class="text-[red]">已离线</span>
                </template>
              </div>
              <el-divider class="card-divider" />
              <div class="card-content" v-show="item.status == 0">
                <div class="card-row" v-if="showField('当前使用模块')">
                  <span class="card-label">当前使用:</span>
                  <span class="card-value" :title="item.moduleName">{{
                    item.moduleName
                  }}</span>
                </div>
                <div
                  class="card-row"
                  v-if="showField('当前学习知识点') && item.catalogName"
                >
                  <span class="card-label">知识点:</span>
                  <span class="card-value" :title="item.catalogName">{{
                    item.catalogName
                  }}</span>
                </div>
                <div class="card-row" v-if="showField('知识点学习时长')">
                  <span class="card-label">时长:</span>
                  <span class="card-use-time card-value">{{
                    item.useTime
                  }}</span>
                </div>
                <div
                  v-if="showField('知识点掌握程度') && item.level"
                  class="card-row"
                >
                  <span class="card-label">掌握程度:</span>
                  <span class="card-value">{{ item.level }}</span>
                </div>
                <div
                  v-if="showField('当前视频名称') && item.videoName"
                  class="card-row"
                >
                  <span class="card-label">视频:</span>
                  <span class="card-value">{{ item.videoName }}</span>
                </div>
                <div
                  v-if="showField('当前视频观看进度') && item.videoTotalTime"
                  class="card-row"
                >
                  <span class="card-label">观看进度:</span>
                  <span class="card-value"
                    >{{ item.videoCurrentTime }}/{{ item.videoTotalTime }}</span
                  >
                </div>
              </div>
            </div>
          </div>
          <transition name="arrow-fade">
            <button
              v-if="showArrows && totalPages > 1"
              class="carousel-arrow right"
              @click="handleManualSwitch('next')"
              @mousedown.stop
            >
              <span class="arrow-icon">&rsaquo;</span>
            </button>
          </transition>
          <div class="carousel-indicator" v-if="totalPages > 1">
            <span
              v-for="n in totalPages"
              :key="n"
              :class="{ active: currentPage === n - 1 }"
              @click="handleIndicatorClick(n - 1)"
            ></span>
          </div>
        </div>
      </template>
      <template v-else>
        <el-empty description="暂无数据" />
      </template>
    </template>
    <template v-else>
      <el-empty :description="tip" />
    </template>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import { checkBoardNo, getRealTimeBoardList } from "@/api/index";
import dayjs from "dayjs";

// 字段选择相关
const showDropdown = ref(false);
const options = ref([
  { label: "累计在线时长", checked: true },
  { label: "当前使用模块", checked: true },
  { label: "当前学习知识点", checked: true },
  { label: "知识点学习时长", checked: true },
  { label: "知识点掌握程度", checked: true },
  { label: "当前视频名称", checked: true },
  { label: "当前视频观看进度", checked: true },
]);
const toggleDropdown = () => {
  showDropdown.value = !showDropdown.value;
};
const dropdownRef = ref(null);
let handleClickOutside = null;
onMounted(() => {
  handleClickOutside = (event) => {
    if (
      !event.target.classList.contains("dropdown-btn") &&
      dropdownRef.value &&
      !dropdownRef.value.contains(event.target)
    ) {
      showDropdown.value = false;
    }
  };
  document.addEventListener("click", handleClickOutside);
});
onUnmounted(() => {
  document.removeEventListener("click", handleClickOutside);
});
// 字段显示判断
const showField = (label) =>
  options.value.find((opt) => opt.label === label)?.checked;

const route = useRoute();
const { id } = route.params;
const num = ref(id);

const isEffective = ref(true);
const tip = ref("看板不存在");
const router = useRouter();
const nowDate = ref(dayjs().format("YYYY-MM-DD HH:mm:ss"));

const boradList = ref([]);
const onlineStuNum = computed(() => {
  return boradList.value.filter((item) => item.status == 0).length;
});
const offlineStuNames = computed(() => {
  return boradList.value
    .filter((item) => item.status == 1)
    .map((item) => item.nickname)
    .join("、");
});

function formatTime(totalSeconds) {
  const hours = Math.floor(totalSeconds / 3600);
  const remainingSeconds = totalSeconds % 3600;
  const minutes = Math.floor(remainingSeconds / 60);
  return `${hours}小时${minutes}分钟`;
}
function formatTimeHHMMSS(totalSeconds) {
  const hours = Math.floor(totalSeconds / 3600);
  const minutes = Math.floor((totalSeconds % 3600) / 60);
  const seconds = totalSeconds % 60;
  return `${hours > 0 ? String(hours).padStart(2, "0") + ":" : ""}${String(
    minutes
  ).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
}

// 轮播相关
const cardContainerRef = ref(null);
const cardItemRef = ref([]);
function setCardItemRef(el) {
  if (el) cardItemRef.value.push(el);
}
const currentPage = ref(0);
const pageSize = ref(1);
const totalPages = computed(() => {
  return pageSize.value > 0
    ? Math.ceil(boradList.value.length / pageSize.value) || 1
    : 0;
});
const pagedList = computed(() => {
  cardItemRef.value = []; // 渲染前清空
  const start = currentPage.value * pageSize.value;
  console.log(
    "计算当前页码",
    currentPage.value,
    boradList.value,
    pageSize.value,
    start
  );
  return boradList.value.slice(start, start + pageSize.value);
});

let autoTimer = null;
let resumeTimer = null;
const autoInterval = 5000;
const resumeDelay = 3000; // 用户无操作3秒后恢复自动轮播
const showArrows = ref(false);
let arrowHideTimer = null;
const virtualCardRef = ref(null);
function calcPageSize() {
  nextTick(() => {
    const container = cardContainerRef.value;
    // 优先用虚拟卡片
    const card =
      virtualCardRef.value || (cardItemRef.value && cardItemRef.value[0]);
    if (!container || !card) return;
    const containerWidth = container.clientWidth;
    const containerHeight = container.clientHeight;
    const cardStyle = getComputedStyle(card);
    const cardWidth =
      card.offsetWidth +
      parseFloat(cardStyle.marginRight || 0) +
      parseFloat(cardStyle.marginLeft || 0);
    const cardHeight =
      card.offsetHeight +
      parseFloat(cardStyle.marginTop || 0) +
      parseFloat(cardStyle.marginBottom || 0);

    // 动态获取gap
    const grid = container.querySelector(".card");
    let cardGap = 24;
    if (grid) {
      const gridStyle = getComputedStyle(grid);
      // 兼容 row-gap/column-gap 以及 gap
      cardGap = parseFloat(gridStyle.columnGap || gridStyle.gap || 24);
    }

    // 修正列数计算，确保不会溢出
    let maxCols = Math.floor(
      (containerWidth + cardGap) / (cardWidth + cardGap)
    );
    maxCols = Math.max(1, maxCols);
    while (
      maxCols > 1 &&
      cardWidth * maxCols + cardGap * (maxCols - 1) > containerWidth + 1
    ) {
      maxCols--;
    }
    const cols = maxCols;

    // 计算最大可放下的完整行数
    let rows = 0;
    let totalHeight = 0;
    while (totalHeight + cardHeight <= containerHeight + 1) {
      rows++;
      totalHeight += cardHeight + cardGap;
    }
    pageSize.value = cols * rows;
    if (currentPage.value >= totalPages.value) {
      currentPage.value = 0;
    }
  });
}
function nextPage() {
  if (totalPages.value <= 0) return;
  currentPage.value = (currentPage.value + 1) % totalPages.value;
}
function prevPage() {
  if (totalPages.value <= 0) return;
  currentPage.value =
    (currentPage.value - 1 + totalPages.value) % totalPages.value;
}
function startAuto() {
  stopAuto();
  autoTimer = setInterval(() => {
    nextPage();
  }, autoInterval);
}
function stopAuto() {
  if (autoTimer) {
    clearInterval(autoTimer);
    autoTimer = null;
  }
}

// 用户操作时停止自动轮播，3秒无操作后恢复
function handleUserActive() {
  stopAuto();
  showArrows.value = true;
  if (resumeTimer) clearTimeout(resumeTimer);
  if (arrowHideTimer) clearTimeout(arrowHideTimer);
  resumeTimer = setTimeout(() => {
    startAuto();
  }, resumeDelay);
  arrowHideTimer = setTimeout(() => {
    showArrows.value = false;
  }, resumeDelay);
}
function handleUserInactive() {
  // 鼠标离开后3秒恢复自动轮播和隐藏按钮
  if (resumeTimer) clearTimeout(resumeTimer);
  if (arrowHideTimer) clearTimeout(arrowHideTimer);
  resumeTimer = setTimeout(() => {
    startAuto();
  }, resumeDelay);
  arrowHideTimer = setTimeout(() => {
    showArrows.value = false;
  }, resumeDelay);
}

function handleManualSwitch(dir) {
  handleUserActive();
  if (dir === "prev") prevPage();
  else nextPage();
}

// 新增：点击指示器跳转对应页面
function handleIndicatorClick(pageIdx) {
  handleUserActive();
  currentPage.value = pageIdx;
}

const getList = async () => {
  try {
    const isNormal = await checkBoardNo({ board_id: id });
    if (isNormal) {
      isEffective.value = false;
      tip.value = isNormal;
      return;
    }
    isEffective.value = true;
    const res = await getRealTimeBoardList({ board_id: id });
    if (Array.isArray(res) && res.length > 0) {
      boradList.value = res.map((item) => {
        const jsonData = item.dataJson ? JSON.parse(item.dataJson) : {};
        return {
          nickname: item.nickname,
          status:
            item.status == 0
              ? dayjs(item.updateTime).isBefore(dayjs().subtract(1, "minute"))
                ? 1
                : 0
              : item.status,
          onlineTime: formatTime(Number(item.onlineTime)),
          moduleName: item.moduleName,
          catalogName: item.catalogName,
          useTime: formatTime(Number(item.useTime)),
          level: item.level,
          videoName: jsonData.videoName || "",
          videoCurrentTime: jsonData.progress
            ? Number(jsonData.progress.split("/")[0]) /
                Number(jsonData.progress.split("/")[1]) >=
              0.99
              ? formatTimeHHMMSS(Number(jsonData.progress.split("/")[1]))
              : formatTimeHHMMSS(Number(jsonData.progress.split("/")[0]))
            : "",
          videoTotalTime: jsonData.progress
            ? formatTimeHHMMSS(Number(jsonData.progress.split("/")[1]))
            : "",
        };
      });
    } else {
      // 伪造数据
      boradList.value = new Array(30).fill(0).map((_, index) => ({
        nickname: `用户${index + 1}`,
        status: index % 2 === 0 ? 0 : 1,
        onlineTime: formatTime(Math.floor(Math.random() * 311113600)),
        moduleName: `模块${index + 1}说的就是领导批示的拍摄大片实打实大苏打`,
        catalogName: index % 3 === 0 ? `知识点${index + 1}` : "",
        useTime: formatTime(Math.floor(Math.random() * 3600)),
        level: index % 4 === 0 ? "掌握" : "未掌握",
        videoName: `视频${index + 1}`,
        videoCurrentTime: formatTimeHHMMSS(Math.floor(Math.random() * 3600)),
        videoTotalTime: formatTimeHHMMSS(Math.floor(Math.random() * 3600)),
      }));
    }
    nextTick(() => {
      setTimeout(calcPageSize, 0);
      setTimeout(calcPageSize, 100);
    });
  } catch (error) {
    console.log(error);
    boradList.value = [];
  }
};

let timer = null;
let timer2 = null;
onMounted(async () => {
  try {
    await getList();
    timer = setInterval(async () => {
      await getList();
    }, 1000 * 10);
    timer2 = setInterval(() => {
      nowDate.value = dayjs().format("YYYY-MM-DD HH:mm:ss");
    }, 1000);

    nextTick(() => {
      setTimeout(calcPageSize, 0);
      setTimeout(calcPageSize, 100);
      startAuto();
    });
    window.addEventListener("resize", calcPageSize);
  } catch (error) {
    console.log(error);
    isEffective.value = false;
    tip.value = "校验看板异常";
  }
});
onUnmounted(() => {
  clearInterval(timer);
  timer = null;
  clearInterval(timer2);
  timer2 = null;
  stopAuto();
  if (resumeTimer) clearTimeout(resumeTimer);
  if (arrowHideTimer) clearTimeout(arrowHideTimer);
  window.removeEventListener("resize", calcPageSize);
});
watch([boradList, cardContainerRef], () => {
  nextTick(() => {
    setTimeout(calcPageSize, 100);
  });
});
</script>

<style lang="scss" scoped>
.board-container {
  height: 100%;
  width: 100%;
  padding: 20px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  position: relative;
  box-sizing: border-box;
}

/* 新增头部flex布局 */
.board-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
  width: 100%;
}

/* 让实时看板号等信息靠左 */
.board-header-info {
  display: flex;
  align-items: center;
  gap: 12px;
  color: #666;
}

/* 字段选择弹窗样式优化 */
.dropdown {
  position: relative;
}

.dropdown-btn {
  padding: 8px 22px;
  cursor: pointer;
  border: 1px solid #ccc;
  background: #fff;
  border-radius: 6px;
  transition: background 0.2s;
  font-size: 20px;
}

.dropdown-btn:hover {
  background: #f5f5f5;
}

.dropdown-menu {
  position: absolute;
  top: 110%;
  right: 0;
  /* 右对齐弹窗 */
  background-color: white;
  border: 1px solid #ccc;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  width: 320px;
  z-index: 1002;
  border-radius: 6px;
  padding: 10px 0;
}

.dropdown-item {
  display: block;
  padding: 14px 32px;
  cursor: pointer;
  user-select: none;
  width: 100%;
  box-sizing: border-box;
}

.dropdown-item:hover {
  background-color: #f0f0f0;
}

.dropdown-item input[type="checkbox"] {
  width: 20px;
  height: 20px;
  margin-right: 12px;
  vertical-align: middle;
}

.board-header {
  color: #666666;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}

.board-num {
  color: #000;
  margin-left: 4px;
  margin-right: 56px;
}

.board-joined {
  margin-right: 48px;
  margin-left: 4px;
}

.board-date {
  margin-left: 0;
}

.board-status {
  color: #666666;
  margin-bottom: 28px;
  min-height: 24px;
}

.board-online {
  color: #000;
  margin-left: 4px;
  margin-right: 48px;
}

.board-offline-names {
  color: #000;
  margin-left: 4px;
}

.card-carousel {
  flex: 1 1 auto;
  position: relative;
  height: 100%;
  display: flex;
  align-items: stretch;
  justify-content: center;
  overflow: hidden;
}

.card {
  flex: 1 1 auto;
  display: grid;
  gap: 24px;
  grid-template-columns: repeat(auto-fit, 286px);
  grid-auto-rows: 243px;
  // justify-content: center;
  // align-content: center;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.card-item {
  width: 286px;
  height: 243px;
  padding: 14px 16px 12px 16px;
  border: 1px solid #ebeef5;
  border-radius: 12px;
  background: #fff;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  overflow: hidden;
}
.virtual-card {
  /* 不影响布局，完全隐藏 */
  position: absolute !important;
  z-index: -1 !important;
  opacity: 0 !important;
  pointer-events: none !important;
}
.card-online-time {
  color: #768895;
  font-weight: normal;
  margin-left: 8px;
  flex-shrink: 0;
  /* 允许自动换行 */
  white-space: normal;
  word-break: break-all;
  margin-left: auto;
}

.card-divider {
  margin: 8px 0 !important;
}

.card-content {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  min-height: 0;
  overflow: hidden;
}

.card-row {
  // display: flex;
  // align-items: center;
  // margin-bottom: 6px;
  // white-space: nowrap;
  // overflow: hidden;
  // text-overflow: ellipsis;
}
.card-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
  color: #333;
}
.card-nickname {
  font-weight: bold;
}
.card-label {
  color: #768895;
  // margin-right: 8px;
  // flex-shrink: 0;
}

.card-value {
  // flex: 1 1 0;
  // min-width: 0;
  // overflow: hidden;
  // text-overflow: ellipsis;
  // display: inline-block;
}

.card-use-time {
  color: #f8ac23;
  margin-left: 4px;
}

.carousel-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(0%);
  z-index: 10;
  width: 40px;
  height: 40px;
  border: none;
  background: rgba(0, 0, 0, 0.2);
  color: #fff;
  font-size: 32px;
  cursor: pointer;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 1;
  transition: opacity 0.3s, visibility 0.3s;
  visibility: visible;
  pointer-events: auto;
}

.arrow-fade-enter-active,
.arrow-fade-leave-active {
  transition: opacity 0.3s, visibility 0.3s;
}

.arrow-fade-enter-from,
.arrow-fade-leave-to {
  opacity: 0;
  visibility: hidden;
}

.carousel-arrow.left {
  left: 10px;
}

.carousel-arrow.right {
  right: 10px;
}

.arrow-icon {
  display: flex;
  justify-content: center;
  width: 100%;
  // height: 100%;
  font-size: 32px;
  align-items: center;
  user-select: none;
}

.carousel-indicator {
  position: absolute;
  bottom: 10px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 8px;

  span {
    display: inline-block;
    width: 12px;
    height: 12px;
    background: #ccc;
    border-radius: 50%;
    cursor: pointer;
    transition: background 0.2s;

    &.active {
      background: #f8ac23;
    }
  }
}
</style>
